package impl

import (
	"context"
	"github.com/redis/go-redis/v9"
	"github.com/robfig/cron/v3"
	distributed2 "go-caipu/pkg/services/schedule/distributed"
	"go-caipu/pkg/services/schedule/distributed/jobs"
	"go-caipu/pkg/setting"
	"gorm.io/gorm"
	"log"
	"os"
	"os/signal"
	"syscall"

	"go-caipu/pkg/services/schedule"
	"go-caipu/pkg/services/schedule/models"
)

type Service struct {
	store     store
	cron      *cron.Cron
	client    *redis.Client
	scheduler *distributed2.TaskScheduler
}

func ProvideService(db *gorm.DB, cfg *setting.Cfg, client *redis.Client) (*Service, error) {
	store := ProvideStore(db)
	s := &Service{
		store:  store,
		cron:   cron.New(cron.WithSeconds()),
		client: client,
	}
	hostname, err := os.Hostname()
	if err != nil {
		hostname = "unknown"
	}
	coordinator := distributed2.NewCoordinator(hostname, cfg.Application.Deploy, s.client)
	go coordinator.MaintainLeadership()

	//初使化任务调度器
	taskScheduler := distributed2.NewTaskScheduler(s, coordinator)
	go taskScheduler.Start()
	s.scheduler = taskScheduler
	taskScheduler.JobList = map[string]distributed2.JobExec{
		"ExamplesOne": jobs.ExamplesOne{},
	}
	return s, nil
}

// Run 启动服务
func (s *Service) Run(ctx context.Context) error {

	//订阅任务更新通知
	s.scheduler.Coordinator.SubscribeTaskUpdates(func(taskID int, action string) {
		switch action {
		case "delete":
			s.scheduler.RemoveTask(taskID)
		case "disable":
			s.scheduler.RemoveTask(taskID)
		case "enable":
			if task, err := s.store.Get(context.Background(), schedule.GetSysJobCommand{JobId: taskID}); err == nil {
				s.scheduler.AddTask(task)
			}
		}
	})

	// 等待终止信号
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	<-sigChan

	// 清理资源
	log.Println("Shutting down task scheduler...")
	s.scheduler.Stop()
	s.scheduler.Coordinator.Stop()
	log.Println("Shutdown  task scheduler complete")
	return nil
}

func (s *Service) GetSysJobPage(ctx context.Context, cmd schedule.GetSysJobPageCommand) (result []schedule.SysJob, num int64, err error) {
	result, num, err = s.store.GetSysJobPage(ctx, cmd)
	if err != nil {
		return
	}
	return
}

func (s *Service) Get(ctx context.Context, cmd schedule.GetSysJobCommand) (schedule.SysJob, error) {
	return s.store.Get(ctx, cmd)
}

func (s *Service) Insert(ctx context.Context, cmd schedule.SysJob) error {
	jobId, err := s.store.Insert(ctx, cmd)
	if err != nil {
		return err
	}
	cmd.JobId = jobId

	err = s.updateSchedule(cmd)

	return err
}
func (s *Service) updateSchedule(cmd schedule.SysJob) error {
	switch cmd.Status {
	case 1:
		if s.scheduler.Coordinator.IsLeader() {
			s.scheduler.AddTask(cmd)
		} else {
			if err := s.scheduler.Coordinator.PublishTaskUpdate(cmd.JobId, "enable"); err != nil {
				return err
			}
		}
	case 0:
		if s.scheduler.Coordinator.IsLeader() {
			s.scheduler.RemoveTask(cmd.JobId)
		} else {
			if err := s.scheduler.Coordinator.PublishTaskUpdate(cmd.JobId, "delete"); err != nil {
				return err
			}
		}
	}
	return nil
}
func (s *Service) Update(ctx context.Context, cmd schedule.SysJob) error {
	// 如果任务已启用，重新调度
	err := s.updateSchedule(cmd)
	if err != nil {
		return err
	}
	return s.store.Update(ctx, cmd)
}

func (s *Service) Remove(ctx context.Context, cmd schedule.RemoveSysJobCommand) error {
	// 从调度器中移除任务
	for _, id := range cmd.Ids {
		if s.scheduler.Coordinator.IsLeader() {
			s.scheduler.RemoveTask(id)
		} else {
			if err := s.scheduler.Coordinator.PublishTaskUpdate(id, "delete"); err != nil {
				return err
			}
		}
	}
	return s.store.Remove(ctx, cmd)
}
func (s *Service) InsertJobLog(ctx context.Context, cmd *models.SysJobLog) error {
	return s.store.InsertJobLog(ctx, cmd)
}
func (s *Service) UpdateJobLog(ctx context.Context, cmd *models.SysJobLog) error {
	return s.store.UpdateJobLog(ctx, cmd)
}
func (s *Service) GetJobLogPage(ctx context.Context, cmd schedule.GetSysJobLogPageCmd) (result []models.SysJobLog, num int64, err error) {
	result, num, err = s.store.GetJobLogPage(ctx, cmd)
	if err != nil {
		return
	}
	return
}
